/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GUI;

import MouseSensorDriver.SaveLoadExp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

/**
 *
 * @author Asko
 */
public class ExperimentContainer implements TableModel, SaveLoadExp {

    ArrayList<Experiment> exps = new ArrayList<>();
    ArrayList<TableModelListener> tml = new ArrayList<>();
    ObjectOutputStream oos = null;
    ObjectInputStream ois = null;
    FileOutputStream fos = null;
    FileInputStream fis = null;
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    private int columnCnt = 16;
    private final int MAX_DIGS_CNT = 3;
    private final int MIN_DIGS_CNT = 0;
    NumberFormat nform = NumberFormat.getInstance();

    public ExperimentContainer() {
        nform.setMaximumFractionDigits(MAX_DIGS_CNT);
        nform.setMinimumFractionDigits(MIN_DIGS_CNT);
    }

    public void add(Experiment ch) {
        exps.add(ch);
        changed();
    }

    public Experiment get(int chNum) {
        return exps.get(chNum);
    }

    public void remove(int chNum) {
        exps.remove(chNum);
        changed();
    }

    public void remove(Experiment obj) {
        exps.remove(obj);
        changed();
    }

    public void removeAll() {
        exps.clear();
        changed();
    }

    public int size() {
        return exps.size();
    }

    private void changed() {
        for (int i = 0; i < tml.size(); i++) {
            tml.get(i).tableChanged(new TableModelEvent(this));
        }
    }

    @Override
    public int getRowCount() {
        return size();
    }

    @Override
    public int getColumnCount() {
        return columnCnt;
    }

    @Override
    public String getColumnName(int columnIndex) {
        switch (columnIndex) {
            case 0: {
                return "#";
            }
            case 1: {
                return "Единицы измерения";
            }
            case 2: {
                return "Начальная позиция";
            }
            case 3: {
                return "Конечная позиция";
            }
            case 4: {
                return "Разница заданных позиций (ед.)";
            }
            case 5: {
                return "Фактическая начальная позиция (ед.)";
            }

            case 6: {
                return "Фактическая конечная позиция (ед.) ";
            }

            case 7: {
                return "Разница фактических позиций (ед.)";
            }

            case 8: {
                return "Датчик перемещения мыши (ед.)";
            }
            case 9: {
                return "Абсолютная погрешность (ед.)";
            }
            case 10: {
                return "Относительная погрешность";
            }
            case 11: {
                return "Время реакции (мс)";
            }
            case 12: {
                return "Сила заданная (Н)";
            }
            case 13: {
                return "Факт. сила (Н)";
            }
            case 14: {
                return "Абс. погр. сила (Н)";
            }
            case 15: {
                return "Отн. погр. сила";
            }

            default:
                return "";
        }
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return String.class;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        switch (columnIndex) {
            case 0: {
                return "" + (rowIndex + 1);
            }
            case 1: {
                return exps.get(rowIndex).getMeasureName();
            }
            case 2: {
                return "" + nform.format(exps.get(rowIndex).getStartPos());
            }
            case 3: {
                return "" + nform.format(exps.get(rowIndex).getEndPos());
            }
            case 4: {
                return "" + nform.format((exps.get(rowIndex).getEndPos()
                        - exps.get(rowIndex).getStartPos()));
            }
            case 5: {
                return "" + nform.format(exps.get(rowIndex).getFactStartPos());
            }

            case 6: {
                return "" + nform.format(exps.get(rowIndex).getFactEndPos());
            }

            case 7: {
                return "" + nform.format((exps.get(rowIndex).getFactEndPos()
                        - exps.get(rowIndex).getFactStartPos()));
            }

            case 8: {
                return "" + nform.format(exps.get(rowIndex).getMousePos());
            }
            case 9: {
                return "" + nform.format(exps.get(rowIndex).getAbsError());
            }
            case 10: {
                return "" + nform.format(exps.get(rowIndex).getRelError());
            }
            case 11: {
                return nform.format(exps.get(rowIndex).getTimeReact());
            }
            case 12: {
                return nform.format(exps.get(rowIndex).getForce());
            }
            case 13: {
                return nform.format(exps.get(rowIndex).getFactForce());
            }
            case 14: {
                return nform.format(exps.get(rowIndex).getAbsErrorForce());
            }
            case 15: {
                double rel = exps.get(rowIndex).getRelErrorForce();
                if (rel != -1) {
                    return nform.format(rel);
                } else {
                    return "none";
                }
            }

            default:
                return "";
        }
    }

    public String getCSV() {
        String buf = "";
        for (int i = 0; i < getColumnCount(); i++) {
            buf += getColumnName(i) + ";";
        }
        buf += "\n";
        for (int i = 0; i < getRowCount(); i++) {
            for (int j = 0; j < getColumnCount(); j++) {
                buf += getValueAt(i, j).toString() + ";";
            }
            buf += "\n";
        }
        return buf;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    }

    @Override
    public void addTableModelListener(TableModelListener l) {
        tml.add(l);
    }

    @Override
    public void removeTableModelListener(TableModelListener l) {
        tml.remove(l);
    }

    public double getSigma() {
        if (exps.size() > 0) {
            double sum = 0;
            for (int i = 0; i < exps.size(); i++) {
                sum += (Math.pow(exps.get(i).getAbsError(), 2)) / exps.size();
            }
            return Math.sqrt(sum);
        } else {
            return -1;
        }
    }

    public double getMaxAbsError() {
        if (exps.size() > 0) {
            double max = exps.get(0).getAbsError();
            double buf;
            for (int i = 1; i < exps.size(); i++) {
                buf = exps.get(i).getAbsError();
                if (max < buf) {
                    max = buf;
                }
            }
            return max;
        } else {
            return -1;
        }
    }

    @Override
    public void saveToFile(File file) {
        try {
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            oos = new ObjectOutputStream(bos);
            for (int i = 0; i < exps.size(); i++) {
                oos.writeObject(exps.get(i));
            }
            //System.out.println("Experiment has been saved to " + file);
            oos.close();
            bos.close();
            fos.close();
        } catch (IOException ex) {
            Logger.getLogger(EndoscopeExpContainer.class.getName()).
                    log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void loadFromFile(File file) {
        this.removeAll();
        try {
            Object obj;
            fis = new FileInputStream(file);
            bis = new BufferedInputStream(fis);
            ois = new ObjectInputStream(bis);
            while ((obj = ois.readObject()) != null) {
                this.add((Experiment) obj);
            }
            ois.close();
            bis.close();
            fis.close();
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(EndoscopeExpContainer.class.
                    getName()).log(Level.SEVERE, null, ex);
        } catch (EOFException ex) {
            //    System.err.println("Reaching eof.");
        } catch (IOException ex) {
            Logger.getLogger(EndoscopeExpContainer.class.
                    getName()).log(Level.SEVERE, null, ex);
        }
    }
}
